package org.dreamwork.jasmine2.web.controls;

import org.dreamwork.jasmine2.engine.HttpContext;
import org.dreamwork.jasmine2.engine.IChangable;
import org.dreamwork.jasmine2.engine.IPostbackHandler;
import org.dreamwork.jasmine2.engine.IValidatable;
import org.dreamwork.jasmine2.events.*;
import org.dreamwork.jasmine2.util.StringConverter;
import org.dreamwork.jasmine2.web.IWebControl;
import org.dreamwork.peony.DataBinder;
import org.dreamwork.util.NameValueCollection;
import org.dreamwork.util.StringUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: seth
 * Date: 2009-7-23
 * Time: 11:37:29
 */
public class DropdownList extends WebContainer implements IPostbackHandler, IChangable, IValidatable {
    protected String textField;
    protected Object selectedValue;
    protected int selectedIndex = -1;
    protected String dataValueField;
    protected Object dataValueSource, selectedItem;

    protected List data;

    protected ChangableDelegate changeDelegate = new ChangableDelegate ();
    protected ValidatableDelegate validateDelegate = new ValidatableDelegate ();

    protected static final String KEY_SELECTED_INDEX = "selectedIndex";
    protected static final String KEY_SELECTED_VALUE = "selectedValue";
    protected static final String KEY_DATA = "data";

    private boolean parsed = false;
//    private boolean dataParsed = false;

    public String getTextField () {
        return textField;
    }

    public void setTextField (String textField) {
        this.textField = textField;
    }

    public int getSelectedIndex () {
        return selectedIndex;
    }

    public String getDataValueField () {
        return dataValueField;
    }

    public void setDataValueField (String dataValueField) {
        this.dataValueField = dataValueField;
    }

    public Object getDataValueSource () {
        return dataValueSource;
    }

    public void setDataValueSource (Object dataValueSource) {
        this.dataValueSource = dataValueSource;
    }

    public Object getSelectedItem () {
        return selectedItem;
    }

    public void setSelectedIndex (int selectedIndex) {
        this.selectedIndex = selectedIndex;
        if (viewStateEnabled)
            stateManager.put (KEY_SELECTED_INDEX, new Integer (selectedIndex));
        if (selectedIndex == -1) {
            selectedValue = null;
            selectedItem = null;
        } else if (data != null && !StringConverter.isEmpty (valueField)) {
            selectedItem = data.get (selectedIndex);
            selectedValue = DataBinder.eval (selectedItem, valueField);
        } else {
            selectedValue = null;
            selectedItem = null;            
        }
    }

    public Object getSelectedValue () {
        return selectedValue;
    }

    public void setSelectedValue (Object value) {
        if (value != null)
            this.selectedValue = value;
        if (data != null && valueField != null) {
            for (int i = 0; i < data.size (); i ++) {
                Object container = data.get (i);
                Object o = DataBinder.eval (container, valueField);
                if (StringConverter.equals (o, selectedValue)) {
                    selectedIndex = i + this.childControls.count ();
                    selectedItem = container;
                    break;
                }
            }
        }
    }

    public void addChangeListener (IChangeListener listener) {
        changeDelegate.addChangeListener (listener);
    }

    public void removeChangeListener (IChangeListener listener) {
        changeDelegate.removeChangeListener (listener);
    }

    public void fireChange (IWebControl sender, String attrName, Object oldValue, Object newValue) throws EventException {
        changeDelegate.fireChange (sender, attrName, oldValue, newValue);
    }

    public IChangeListener[] getChangeListeners () {
        return changeDelegate.getChangeListeners ();
    }

    public void addValidateListener (IValidateListener listener) {
        validateDelegate.addValidateListener (listener);
    }

    public void removeValidateListener (IValidateListener listener) {
        validateDelegate.removeValidateListener (listener);
    }

    public IValidateListener[] getValidateListners () {
        return validateDelegate.getValidateListners ();
    }

    public boolean fireValidateListeners (IWebControl sender) {
        return validateDelegate.fireValidateListeners (sender);
    }

    public void addControl (IWebControl control) {
        if (control.getClass () != ListItem.class)
            throw new IllegalArgumentException (control.getClass ().getName ());
        super.addControl (control);
    }

    public void init () {
        super.init ();
        htmlTagName = "select";
    }

    public void postbackData (NameValueCollection props) {
        String value = props.getValue (id);
        if (value != null) selectedValue = value;
        if (data != null && valueField != null && selectedValue != null) for (int i = 0; i < data.size (); i ++) {
            Object container = data.get (i);
            Object current = DataBinder.eval (container, valueField);
            if (StringConverter.equals (selectedValue, current)) {
                selectedIndex = i;
                selectedItem = container;
                break;
            }
        }
    }

    @Override
    protected void loadViewState (Object savedState) throws IOException {
        super.loadViewState (savedState);
        List list = (List) stateManager.get (KEY_DATA);
        if (list != null) data = list;

        Integer index = (Integer) stateManager.get (KEY_SELECTED_INDEX);
        if (index != null)
            oldAttributes.put (KEY_SELECTED_INDEX, index);
        Object value = stateManager.get (KEY_SELECTED_VALUE);
        if (value != null)
            oldAttributes.put (KEY_SELECTED_VALUE, value);
    }

    @SuppressWarnings ("unchecked")
    public void onDataBind (Object sender) throws EventException {
        if (this.childControlCreated) return;
        super.onDataBind (sender);
        if (dataSource != null) {
            data = DataBinder.parseDataSource (dataSource, null);
            parsed = true;
        }

        String e = getDynamicAttribute ("name");
        if (!StringUtil.isEmpty (e)) try {
            Object o = this.getPage ().eval (e.trim ());
            if (o != null) {
                attrs.setProperty ("name", o.toString ());
            }
        } catch (Exception ex) {
            ex.printStackTrace ();
            try {
                Object o = this.getPage ().eval (e.trim ());
            } catch (Exception ee) {
                //
            }
        }

        e = getDynamicAttribute ("clientId");
        if (!StringUtil.isEmpty (e)) try {
            Object o = this.getPage ().eval (e.trim ());
            if (o != null) {
                attrs.setProperty ("id", o.toString ());
            }
        } catch (Exception ex) {
            ex.printStackTrace ();
        }

        List tmp = new ArrayList ();
        try {
            if (dataValueSource == null) {
                String expression = this.getDynamicAttribute ("datavaluesource");
                if (expression != null)
                    dataValueSource = page.eval (expression);
            }

            if (dataValueSource != null && !StringConverter.isEmpty (dataValueField)) {
                setSelectedValue (DataBinder.eval (dataValueSource, dataValueField));
            } else {
                String expression = getDynamicAttribute ("selectedvalue");
                if (!StringConverter.isEmpty (expression)) {
                    selectedValue = page.eval (expression);
                }
            }

            if (selectedValue == null && attrs.containsKey ("selectedvalue")) {
                selectedValue = getAttribute ("selectedvalue");
            }
        } catch (Throwable t) {
            throw new EventException (t);
        }

        if (viewStateEnabled) {
            for (int i = 0; i < childControls.count (); i ++) {
                ListItem item = (ListItem) childControls.get (i);
                tmp.add (item.getValue ());
            }
            if (data != null) merge (tmp, data);
            stateManager.put (KEY_DATA, tmp);
        }

        createChildControls ();
        childControlCreated = true;
    }

    private void merge (List a, List b) {
        for (Object o : b) {
            if (!a.contains (o)) a.add (o);
        }
    }

    public void createChildControls () {
        if (childControlCreated) return;
        int offset = childControls.count ();
        List<ListItem> list = new ArrayList<ListItem> ();
        for (int i = 0; i < offset; i++) {
            ListItem item = (ListItem) childControls.get (i);
            item.setSelected (false);
            if (StringConverter.equals (selectedValue, item.getValue ())) {
                selectedIndex = i;
                item.setSelected (true);
                list.add (item);
            }
        }

        int last = -1;
        if (data != null && !StringUtil.isEmpty (valueField)) for (int i = parsed ? 0 : offset; i < data.size (); i++) {
            ListItem item = new ListItem ();
            item.setId (this.id + '_' + (i + offset));
            Object container = data.get (i);
            Object value = DataBinder.eval (container, valueField);
            Object text = DataBinder.eval (container, textField);
            item.setValue (StringConverter.contvertToString (value));
            item.setText (StringConverter.contvertToString (text));
            if (StringConverter.stringEquals (selectedValue, value)) {
                last ++;
                selectedIndex = parsed ? i + offset : i;
                list.add (item);
                selectedItem = container;
            }
            addControl (item);
        }

        if (this.childControls.count () > 0 && selectedIndex > -1) {
            ((ListItem) this.childControls.get (selectedIndex)).setSelected (true);
        }
        stateManager.put (KEY_SELECTED_INDEX, selectedIndex);
        stateManager.put (KEY_SELECTED_VALUE, selectedValue);
    }

    public void onPrerender (IWebControl sender, HttpContext context) throws EventException {
//        setAttribute ("name", id);
        if (!attrs.containsKey ("name")) {
            if (!StringUtil.isEmpty (this.name)) {
                setAttribute ("name", this.name);
            } else {
                setAttribute ("name", this.getClientId ());
            }
        }
        if (runAtServer && autoPostback) {
            page.registerClientScriptBlock (InternalJS.class, InternalJS.ON_CLICK_JS);
            attrs.setProperty ("onchange", "__client_stub (this, 'change', '" + KEY_SELECTED_VALUE + "')");
        }        
    }

    @Override
    public IWebControl copy () {
        try {
            DropdownList dl = (DropdownList) super.baseCopy ();
            dl.textField = textField;
            dl.selectedValue = selectedValue;
            dl.selectedIndex = selectedIndex;
            dl.selectedItem = selectedItem;
            dl.dataValueField = dataValueField;
            dl.dataValueSource = dataValueSource;
            return dl;
        } catch (Exception ex) {
            return super.copy ();
        }
    }
}